using System;
using System.Collections;
using System.ComponentModel.Design;
using System.IO;
using System.Resources;
using EnvDTE;
using VSSDKAssist.Assets.Helpers;

namespace VSSDKAssist.Recipes.Common.Helpers
{
	/// <summary>
	/// Resx Helper class
	/// </summary>
	public static class ResxHelper
	{
		private const string DrawingBitmap = @"System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
		private const string DrawingIcon = @"System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";

		/// <summary>
		/// Gets the type of the RESX.
		/// </summary>
		/// <param name="filename">The filename.</param>
		/// <returns></returns>
		public static string GetResxType(string filename)
		{
			Guard.ArgumentNotNullOrEmptyString(filename, "filename");

			string extension = Path.GetExtension(filename);

			if(extension.Equals(".bmp", StringComparison.OrdinalIgnoreCase) ||
				extension.Equals(".gif", StringComparison.OrdinalIgnoreCase) ||
				extension.Equals(".jpg", StringComparison.OrdinalIgnoreCase))
			{
				return DrawingBitmap;
			}
			else if(extension.Equals(".ico", StringComparison.OrdinalIgnoreCase))
			{
				return DrawingIcon;
			}

			return DrawingBitmap;
		}

		/// <summary>
		/// Gets the RESX data node by id.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="resxFileName">Name of the RESX file.</param>
		/// <param name="textResourceId">The text resource id.</param>
		/// <returns></returns>
		public static ResXDataNode GetResxDataNodeById(IServiceProvider serviceProvider, string resxFileName, string textResourceId)
		{
			Guard.ArgumentNotNull(serviceProvider, "serviceProvider");
			Guard.ArgumentNotNullOrEmptyString(resxFileName, "resxFileName");
			Guard.ArgumentNotNullOrEmptyString(textResourceId, "textResourceId");

			ResXDataNode node = null;

			using(ResXResourceReader reader = new ResXResourceReader(resxFileName))
			{
				reader.BasePath = Path.GetDirectoryName(resxFileName);
				reader.UseResXDataNodes = true;

				IDictionaryEnumerator enu = reader.GetEnumerator();

				while(enu.MoveNext())
				{
					if(enu.Key.ToString().Equals(textResourceId))
					{
						node = enu.Value as ResXDataNode;
						break;
					}
				}

				reader.Close();
			}

			return node;
		}

		/// <summary>
		/// Gets the RESX data node by text value.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="resxFileName">Name of the RESX file.</param>
		/// <param name="textResourceValue">The text resource value.</param>
		/// <returns></returns>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public static ResXDataNode GetResxDataNodeByTextValue(IServiceProvider serviceProvider, string resxFileName, string textResourceValue)
		{
			Guard.ArgumentNotNull(serviceProvider, "serviceProvider");
			Guard.ArgumentNotNullOrEmptyString(resxFileName, "resxFileName");
			Guard.ArgumentNotNullOrEmptyString(textResourceValue, "textResourceValue");

			ResXDataNode node = null;
			ITypeResolutionService typeResolutionService =
				serviceProvider.GetService(typeof(ITypeResolutionService)) as ITypeResolutionService;

			using(ResXResourceReader reader = new ResXResourceReader(resxFileName))
			{
				reader.BasePath = Path.GetDirectoryName(resxFileName);
				reader.UseResXDataNodes = true;

				IDictionaryEnumerator enu = reader.GetEnumerator();

				while(enu.MoveNext())
				{
					ResXDataNode nodeTemp = enu.Value as ResXDataNode;

					if(nodeTemp.GetValue(typeResolutionService).ToString().Equals(textResourceValue))
					{
						node = nodeTemp;
						break;
					}
				}

				reader.Close();
			}

			return node;
		}

		/// <summary>
		/// Gets the RESX text value by id.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="resxFileName">Name of the RESX file.</param>
		/// <param name="textResourceId">The text resource id.</param>
		/// <returns></returns>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public static string GetResxTextValueById(IServiceProvider serviceProvider, string resxFileName, string textResourceId)
		{
			Guard.ArgumentNotNull(serviceProvider, "serviceProvider");
			Guard.ArgumentNotNullOrEmptyString(resxFileName, "resxFileName");
			Guard.ArgumentNotNullOrEmptyString(textResourceId, "textResourceId");

			string resxValue = null;
			ITypeResolutionService typeResolutionService =
				serviceProvider.GetService(typeof(ITypeResolutionService)) as ITypeResolutionService;

			ResXDataNode node = GetResxDataNodeById(serviceProvider, resxFileName, textResourceId);

			if(node != null && typeResolutionService != null)
			{
				resxValue = node.GetValue(typeResolutionService).ToString();
			}

			return resxValue;
		}

		/// <summary>
		/// Gets the RESX id by text value.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		/// <param name="resxFileName">Name of the RESX file.</param>
		/// <param name="textResourceValue">The text resource value.</param>
		/// <returns></returns>
		public static string GetResxIdByTextValue(IServiceProvider serviceProvider, string resxFileName, string textResourceValue)
		{
			Guard.ArgumentNotNull(serviceProvider, "serviceProvider");
			Guard.ArgumentNotNullOrEmptyString(resxFileName, "resxFileName");
			Guard.ArgumentNotNullOrEmptyString(textResourceValue, "textResourceValue");

			string resxId = null;
			ResXDataNode node = GetResxDataNodeByTextValue(serviceProvider, resxFileName, textResourceValue);

			if(node != null)
			{
				resxId = node.Name;
			}

			return resxId;
		}

		/// <summary>
		/// Updates the RESX entry.
		/// </summary>
		/// <param name="resxProjectItem">The RESX project item.</param>
		/// <param name="node">The node.</param>
		/// <param name="resourceId">The resource id.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public static void UpdateResxEntry(ProjectItem resxProjectItem, ResXDataNode node, string resourceId)
		{
			Guard.ArgumentNotNull(resxProjectItem, "resxProjectItem");
			Guard.ArgumentNotNull(node, "node");
			Guard.ArgumentNotNullOrEmptyString(resourceId, "resourceId");

			string resxFileName = resxProjectItem.Properties.Item("FullPath").Value.ToString();

			ResXResourceReader reader = new ResXResourceReader(resxFileName);
			reader.BasePath = Path.GetDirectoryName(resxFileName);
			reader.UseResXDataNodes = true;

			using(ResXResourceWriter writer = new ResXResourceWriter(resxFileName))
			{
				IDictionaryEnumerator enu = reader.GetEnumerator();

				while(enu.MoveNext())
				{
					ResXDataNode nodeTemp1 = enu.Value as ResXDataNode;

					if(nodeTemp1.FileRef != null)
					{
						//Bitmap entries
						if(enu.Key.ToString().Equals(resourceId))
						{
							writer.AddResource(enu.Key.ToString(), node);
						}
						else
						{
							ResXFileRef fileRefTemp = new ResXFileRef(
								VSIPHelper.GetRelativePath(
									resxProjectItem.ContainingProject,
									nodeTemp1.FileRef.FileName),
									GetResxType(nodeTemp1.FileRef.FileName));

							ResXDataNode nodeTemp2 = new ResXDataNode(enu.Key.ToString(), fileRefTemp);
							writer.AddResource(nodeTemp2);
						}
					}
					else
					{
						//Text entries
						if(enu.Key.ToString().Equals(resourceId))
						{
							writer.AddResource(enu.Key.ToString(), node);
						}
						else
						{
							writer.AddResource(enu.Key.ToString(), enu.Value);
						}
					}
				}
				
				writer.Close();
			}

			reader.Close();
		}

		/// <summary>
		/// Appends the bitmap RESX entry.
		/// </summary>
		/// <param name="resxProjectItem">The RESX project item.</param>
		/// <param name="bitmapProjectItem">The bitmap project item.</param>
		/// <param name="bitmapResourceId">The bitmap resource id.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public static void AppendBitmapResxEntry(ProjectItem resxProjectItem, ProjectItem bitmapProjectItem, string bitmapResourceId)
		{
			Guard.ArgumentNotNull(resxProjectItem, "resxProjectItem");
			Guard.ArgumentNotNull(bitmapProjectItem, "bitmapProjectItem");
			Guard.ArgumentNotNullOrEmptyString(bitmapResourceId, "bitmapResourceId");

			string resxFileName = resxProjectItem.Properties.Item("FullPath").Value.ToString();
			string bitmapFileName = VSIPHelper.GetRelativePath(bitmapProjectItem.ContainingProject, bitmapProjectItem);

			ResXResourceReader reader = new ResXResourceReader(resxFileName);
			reader.BasePath = Path.GetDirectoryName(resxFileName);
			reader.UseResXDataNodes = true;

			using(ResXResourceWriter writer = new ResXResourceWriter(resxFileName))
			{
				IDictionaryEnumerator enu = reader.GetEnumerator();

				while(enu.MoveNext())
				{
					ResXDataNode nodeTemp1 = enu.Value as ResXDataNode;

					if(nodeTemp1.FileRef != null)
					{
						ResXFileRef fileRefTemp = new ResXFileRef(
							VSIPHelper.GetRelativePath(
								bitmapProjectItem.ContainingProject,
								nodeTemp1.FileRef.FileName),
                                GetResxType(nodeTemp1.FileRef.FileName));
						ResXDataNode nodeTemp2 = new ResXDataNode(enu.Key.ToString(), fileRefTemp);
						writer.AddResource(nodeTemp2);
					}
					else
					{
						writer.AddResource(enu.Key.ToString(), enu.Value);
					}
				}

				ResXFileRef fileRef = new ResXFileRef(bitmapFileName, GetResxType(bitmapFileName));
				ResXDataNode node = new ResXDataNode(bitmapResourceId, fileRef);
				writer.AddResource(node);

				writer.Close();
			}

			reader.Close();
		}

		/// <summary>
		/// Appends the text RESX entry.
		/// </summary>
		/// <param name="resxProjectItem">The RESX project item.</param>
		/// <param name="textResourceId">The text resource id.</param>
		/// <param name="textValue">The text value.</param>
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:ValidateArgumentsOfPublicMethods")]
		public static void AppendTextResxEntry(ProjectItem resxProjectItem, string textResourceId, string textValue)
		{
			Guard.ArgumentNotNull(resxProjectItem, "resxProjectItem");
			Guard.ArgumentNotNullOrEmptyString(textResourceId, "textResourceId");
			Guard.ArgumentNotNullOrEmptyString(textValue, "textValue");

			string resxFileName = resxProjectItem.Properties.Item("FullPath").Value.ToString();

			ResXResourceReader reader = new ResXResourceReader(resxFileName);
			reader.BasePath = Path.GetDirectoryName(resxFileName);
			reader.UseResXDataNodes = true;

			using(ResXResourceWriter writer = new ResXResourceWriter(resxFileName))
			{
				IDictionaryEnumerator enu = reader.GetEnumerator();

				while(enu.MoveNext())
				{
					ResXDataNode nodeTemp1 = enu.Value as ResXDataNode;

					if(nodeTemp1.FileRef != null)
					{
						ResXFileRef fileRefTemp = new ResXFileRef(
							VSIPHelper.GetRelativePath(
								resxProjectItem.ContainingProject,
								nodeTemp1.FileRef.FileName),
								GetResxType(nodeTemp1.FileRef.FileName));

						ResXDataNode nodeTemp2 = new ResXDataNode(enu.Key.ToString(), fileRefTemp);
						writer.AddResource(nodeTemp2);
					}
					else
					{
						writer.AddResource(enu.Key.ToString(), enu.Value);
					}
				}

				ResXDataNode node = new ResXDataNode(textResourceId, textValue);
				writer.AddResource(node);				
				writer.Close();
			}

			reader.Close();
		}
	}
}